home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
simula
/
books
/
books.lha
/
kirkerud
/
nim.sim
< prev
next >
Wrap
Text File
|
1993-08-16
|
10KB
|
283 lines
% ****************************************************************
% * *
% * This is the program constructed in chapter 10 of *
% * Object Oriented Programming with Simula by Bj|rn Kirkerud; *
% * *
% ****************************************************************
begin
class Nim_player(initial_heap_size, max_matches_in_move);
integer initial_heap_size, max_matches_in_move;
virtual:
procedure another_game is Boolean procedure another_game;;
procedure move is integer procedure move(heap_size); integer heap_size;;
procedure Game_over is procedure Game_over(victory); Boolean victory;;
! By specifying these procedures to be virtual we allow
! each type of Nim_player to have special versions of them;
begin
! There are no attributes which all kinds of Nim_player's share
! except initial_heap_size and max_matches_in_move
! and no imperatives which all Nim_player's share.
! The body of a general Nim_player is therefore empty;
end of Nim_player;
Nim_player class Human;
protected human_name, Give_instructions;
begin
character human_name; ! character should be changed to text
! when we know how to handle text variables;
Boolean procedure another_game;
begin
outtext("Another game "); outchar(human_name);
another_game := prompt_for_bool("? ");
end of another_game;
integer procedure move(heap_size); integer heap_size;
begin integer user_move;
outtext("There are now ");
outint(heap_size, 0); outtext(" matches in the heap. ");
user_move := prompt_for_int("What is your move? ");
while not(1 le user_move and user_move le
min(heap_size, max_matches_in_move)) do
begin
User_message("Illegal move!");
outtext("You must take at least 1 but never more than ");
outint(max_matches_in_move, 0); outtext(" matches"); outimage;
if prompt_for_bool("Perhaps you want instructions? ")
then Give_instructions;
user_move := prompt_for_int("Give a legal move> ");
end;
move := user_move;
end of move;
procedure Game_over(victory); Boolean victory;
begin
outtext(if victory then "Congratulations " else "Sorry ");
outchar(human_name);
outtext(if victory then "! You won!"
else ", you lost. Better luck(?) next time.");
outimage; outimage;
end;
procedure Give_instructions;
User_message("Sorry, no instructions are available "
"in the current implementation.");
! Initialization: ;
user_message("Welcome to the game of Nim!");
human_name := prompt_for_char("What is your name? ");
if prompt_for_bool("Do you want instructions? ")
then Give_instructions;
end of Human;
Nim_player class Machine;
protected compute_move, gagged;
virtual: integer procedure compute_move;
begin
Boolean procedure another_game;
another_game := true;
! A machine is always ready for another game;
integer procedure move(heap_size); integer heap_size;
begin integer my_move;
my_move := compute_move(heap_size);
if not gagged then
begin
outtext("It is my turn, with "); outint(heap_size, 0);
outtext(" matches in the heap. I take ");
outint(my_move, 0); outimage;
end;
move := my_move;
end of move;
Boolean gagged;
procedure ungag; gagged := false;
procedure gag; gagged := true;
! Initialization: ;
gagged := false;
end of Machine;
Machine class Learning_machine;
protected beads, history, seed;
begin
integer array beads(1 : initial_heap_size, 1 : max_matches_in_move),
history(1 : initial_heap_size);
integer seed;
integer procedure compute_move(heap_size); integer heap_size;
begin integer move, max_move, sum_beads, random_bead;
max_move := min(heap_size, max_matches_in_move);
for move := 1 step 1 until max_move do
sum_beads := sum_beads + beads(heap_size, move);
if sum_beads = 0 then
move := randint(1, max_move, seed)
else begin
random_bead := randint(1, sum_beads, seed);
move := 1; sum_beads := beads(heap_size, 1);
while sum_beads < random_bead do
begin
move := move + 1;
sum_beads := sum_beads + beads(heap_size, move);
end;
end;
history(heap_size) := move;
compute_move := move;
end of compute_move;
procedure Game_over(victory); Boolean victory;
begin integer heap_size;
for heap_size := 1 step 1 until initial_heap_size do
if history(heap_size) > 0 then
begin
beads(heap_size, history(heap_size))
:= max(0, beads(heap_size, history(heap_size))
+ (if victory then 1 else -1));
history(heap_size) := 0;
end;
end of Game_over;
! Initialization: ;
begin integer heap_size, move;
for heap_size := 1 step 1 until initial_heap_size do
for move := 1 step 1 until min(heap_size, max_matches_in_move) do
beads(heap_size, move) := 4;
seed := 1234179;
end of Initialization;
end of Learning_machine;
Learning_machine class Automatic_learner;
protected Automatic_training, Write_odds;
begin
procedure Automatic_training;
begin
integer round_number; Boolean more_training;
ref(Learning_machine) sparring_partner;
sparring_partner
:- new Learning_machine(initial_heap_size, max_matches_in_move);
User_message("Start of training against a sparring partner");
gag; sparring_partner.gag;
! This is to ensure that no moves are written during training;
round_number := 1; more_training := true;
while more_training do
begin
Series_of_games(this Nim_player, sparring_partner,
100, initial_heap_size);
! The procedure Series_of_games is declared below;
outimage; outtext("Odds after "); outint(round_number*100, 0);
outtext(" training games:"); outimage;
Write_odds;
round_number := round_number + 1;
more_training := not prompt_for_bool("Stop training now? ");
end;
ungag; ! The training is over, and moves should be written henceforth;
end of Automatic_training;
procedure Write_odds;
begin integer heap_size, move_number;
for heap_size := 1 step 1 until initial_heap_size do
begin
outint(heap_size, 4); outtext(": ");
for move_number := 1 step 1 until
min(heap_size, max_matches_in_move)
do outint(beads(heap_size, move_number), 5);
outimage;
end;
end of Write_odds;
! Initialization: ;
Automatic_training;
end of Automatic_learner;
procedure One_game(player_1, player_2, heap_size, player_1_first);
ref(Nim_player) player_1, player_2;
integer heap_size; Boolean player_1_first;
! Conducts a single game between player_1 and player_2
! Lets player_1 start if player_1_first is true;
begin
Boolean player_1_to_move;
player_1_to_move := player_1_first;
while heap_size > 0 do
begin
heap_size := heap_size - (if player_1_to_move
then player_1 . move(heap_size)
else player_2 . move(heap_size));
player_1_to_move := not player_1_to_move;
end;
player_1 . Game_over(player_1_to_move);
player_2 . Game_over(not player_1_to_move);
end;
procedure Tournament(player_1, player_2, heap_size);
ref(Nim_player) player_1, player_2; integer heap_size;
begin Boolean player_1_first;
player_1_first := true; ! player_1 moves first in the first game;
while player_1 . another_game and then player_2 . another_game do
begin
One_game(player_1, player_2, heap_size, player_1_first);
! Alternate who moves first: ;
player_1_first := not player_1_first;
end;
end of Tournament;
procedure Series_of_games(player_1, player_2, number_of_games, heap_size);
ref(Nim_player) player_1, player_2;
integer number_of_games, heap_size;
begin
integer game_number; Boolean player_1_first;
player_1_first := true;
for game_number := 1 step 1 until number_of_games do
begin
One_game(player_1, player_2, heap_size, player_1_first);
player_1_first := not player_1_first;
end;
end of Series_of_games;
Boolean procedure prompt_for_bool(prompt); text prompt;
begin character c;
outtext(prompt); breakoutimage; inimage;
c := inchar;
prompt_for_bool := c = 'y' or c = 'Y';
end;
integer procedure prompt_for_int(prompt); text prompt;
begin
outtext(prompt); breakoutimage; inimage;
prompt_for_int := inint;
end;
character procedure prompt_for_char(prompt); text prompt;
begin
outtext(prompt); breakoutimage; inimage;
prompt_for_char := inchar;
end;
procedure User_message(message); text message;
begin outtext(message); outimage end;
Tournament(new Human(15, 5), new Automatic_learner(15, 5), 15);
end